package com.uziot.boot.annotions;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.Map;
import java.util.Objects;

/**
 * @author detao
 */

@Slf4j
@Configuration
public class AutoBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {

        //构造bean定义
        BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(AutoBean.class);
        BeanDefinition beanDefinition = beanDefinitionBuilder.getRawBeanDefinition();
        //注册bean定义
        registry.registerBeanDefinition("autoBean", beanDefinition);
        // AutoDIBean 的注入方式
        beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(AutoDIBean.class);
        beanDefinitionBuilder.addConstructorArgValue("自动注入依赖Bean");
        beanDefinition = beanDefinitionBuilder.getBeanDefinition();
        registry.registerBeanDefinition("autoDiBean", beanDefinition);

        // 注册Bean定义，容器根据定义返回bean
        String[] beanDefinitionNames = registry.getBeanDefinitionNames();
        ArrayList<Class<?>> parentClass = new ArrayList<>();
        for (String beanDefinitionName : beanDefinitionNames) {
            BeanDefinition definition = registry.getBeanDefinition(beanDefinitionName);
            String beanClassName = definition.getBeanClassName();
            if (null == beanClassName) {
                continue;
            }
            try {
                // 获取到所注解标注的父类的class
                Class<?> className = Class.forName(beanClassName);
                if (className.isAnnotationPresent(Log.class)) {
                    Class<?> superClassName = className.getSuperclass();
                    parentClass.add(superClassName);
                }
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
        // 移除注册父类的注册Bean
        if (!parentClass.isEmpty()) {
            parentClass.forEach(clazz -> {
                // 在注册工厂中找到所有父类标注的类型，并将其移除
                for (String beanDefinitionName : beanDefinitionNames) {
                    BeanDefinition definition = registry.getBeanDefinition(beanDefinitionName);
                    if (Objects.equals(definition.getBeanClassName(), clazz.getName())) {
                        registry.removeBeanDefinition(beanDefinitionName);
                        log.info("===========>移除注册对象：{},使用子类类对象", beanDefinitionName);
                    }
                }
            });
        }
        parentClass.clear();
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory factory) throws BeansException {
        // 注册Bean实例，使用supply接口, 可以创建一个实例，并主动注入一些依赖的Bean；当这个实例对象是通过动态代理这种框架生成时，就比较有用了
        BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(AutoFacDIBean.class, () -> {
            AutoFacDIBean autoFacDiBean = new AutoFacDIBean("autoFac");
            autoFacDiBean.setAutoBean(factory.getBean("autoBean", AutoBean.class));
            autoFacDiBean.setOriginBean(factory.getBean("originBean", OriginBean.class));
            return autoFacDiBean;
        });
        DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) factory;
        BeanDefinition beanDefinition = builder.getRawBeanDefinition();
        beanFactory.registerBeanDefinition("autoFacDIBean", beanDefinition);
    }
}
